#######################################################################
#                                                                     #
# Title:        TWISP 1.0                                             #
# Author:       pezhore                                               #
#                                                                     #
# Description:  Evaluates followers for potential spammers based on   #
#               (1) Number of friends v. followers                    #
#               (2) Bio keywords                                      #
#               (3) Number of friends with regards to age of account  #
#               (4) If they've got a bio pic                          #
#                                                                     #
# Requrements:  Powershell v2 CTP2, Twitter Account                   #
#                                                                     #
# Usage:        .\twisp.ps1 [-minSpammer n]                           #
#               Optionally specify minimum index of spamitude         #
#                                                                     #
# Changelog:                                                          #
#   1.0   Finalized DM and Blocking capabilities                      #
#   0.9   Added Direct Message Capability                             #
#   0.8   Added Basic GUI                                             #
#   0.7   Added full twitter functionality                            #
#   0.1   Initial revision                                            #
#                                                                     #
#######################################################################
#requires -version 2

# Parameter for custom index of spamitude
param([int]$minSpammer = 8)

[void] [Reflection.Assembly]::LoadWithPartialName("System.Web") 
[void] [Reflection.Assembly]::LoadWithPartialName("System.Text") 

# Twitter doesn't return 100 codes, so turn expect 100 off
[System.Net.ServicePointManager]::Expect100Continue = $false;

# Script wide credentials
$script:g_creds = $null;

# Create Type Twit to contain user information
add-type @"
public struct Twit {
   public string  Name;        
   public int     Followers;   
   public int     Friends;     
   public int     Age;         
   public string  Bio;         
   public bool    hasPic;      
   public int     index;       
}
"@

#-------------------------------------------
# get-BioIndex
# Description:  returns the spammer index based on the $person's bio
#               based on keywords split by ','
# Parameters:   [twit]$person
# Output:       [int]$index
#
#-------------------------------------------
function get-bioIndex([twit]$person, [string]$keywords){
  
  # Set default index to 0
  $index = 0
  
  # Get $person's Bio
  $bio = $person.Bio
  
  # Begin Evaluation
  if ($bio -match "(?i)\bweb.?2\.0")    {$index += 3}
  if ($bio -match "(?i)\bfollow.?me")   {$index += 4}
  if ($bio -match "(?i)http://")        {$index += 4}
  if ($bio -match "(?i)\bexpert")       {$index += 4}
  if ($bio -match "(?i)\bsocial")       {$index += 5}
  if ( ($bio -match "(?i)\bmedia.?") -and ($bio -match "(?i)\expert") ) {$index += 5}
  if ($bio -match "(?i)\\bfollowers")   {$index += 7}
  if ($bio -match "(?i)\bSEO")          {$index += 8}
  if ($bio -match "(?i)\bcash")         {$index += 10}
  
  return $index
} #end function get-FriendIndex

#-------------------------------------------
# get-FriendIndex
# Description:  returns the spammer index based on the $person's number of
#               friends with regard to $person's age (in days)
# Parameters:   [twit]$person
# Output:       [int]$index
#
#-------------------------------------------
function get-FriendIndex([twit]$person){
  
  # Set default index to 0
  $index = 0
  
  # Begin Evaluation
  if ( ($person.friends -gt 300) -and ($person.friends -le 700) ){
    switch($person.age){
      {$_ -le 2} {$index = 5}
      {($_ -gt 2) -and ($_ -le 10)}{$index = 4}
      {($_ -gt 10) -and ($_ -le 20)}{$index = 2}
      {$_ -gt 20}{$index = 1}
    }
  }elseif ( ($person.friends -gt 700) -and ($person.friends -le 1000) ){
    switch($person.age){ 
      {$_ -le 2} {$index = 8}
      {($_ -gt 2) -and ($_ -le 10)}{$index = 7}
      {($_ -gt 10) -and ($_ -le 20)}{$index = 6}
      {$_ -gt 20}{$index = 5}
    }    
  }elseif ( ($person.friends -gt 1000) -and ($person.friends -le 3000) ){
    switch($person.age){
      {$_ -le 2} {$index = 10}
      {($_ -gt 2) -and ($_ -le 10)}{$index = 10}
      {($_ -gt 10) -and ($_ -le 20)}{$index = 9}
      {$_ -gt 20}{$index = 8}
    }
  }elseif ( $person.friends -gt 3000 ){
    $index = 10
  }

  # Return index
  return $index
} # END function get-FriendIndex

#-------------------------------------------
# get-RatioIndex
# Description:  returns the spammer index based on the $person's ratio of
#               friends to followers
# Parameters:   [twit]$person
# Output:       [int]$index
#
#-------------------------------------------
function get-RatioIndex([twit]$person){
  
  # Set default index to 0
  $index = 0 
  
  # Begin Evaluation
  if ($person.followers -eq 0){ # $person has no followers
    switch($person.friends){
      {$_ -le 150} {$index = 0}                       # Follows 150 people with zero followers
      {($_ -gt 150) -and ($_ -le 300)} {$index = 3}   # Follows 151-300 people with zero followers
      {($_ -gt 300) -and ($_ -le 500)} {$index = 6}   # Follows 301-500 people with zero followers
      {($_ -gt 500) -and ($_ -le 700)} {$index = 8}   # Follows 501-700 people with zero followers
      {$_ -gt 700} {$index = 10}                      # Follows over 700 people with zero followers
    } 
  }else{   # $person has followers
    $ratio = $person.friends / $person.followers      # Set Ratio
    if ($person.friends -le 500){   # Follows less than 500 people
      switch($ratio){
        {$_ -le 1} {$index = -1}    # Ratio is less than 1, i.e. more followers than friends
        {($_ -gt 1) -and ($_ -le 1.5)}{$index = 1}
        {($_ -gt 1.5) -and ($_ -le 2)}{$index = 3}
        {($_ -gt 2) -and ($_ -le 2.5)}{$index = 4}
        {($_ -gt 2.5) -and ($_ -le 3)}{$index = 6}
        {$_ -gt 3}{$index = 9}
      }
    }elseif ( ($person.friends -gt 500) -and ($person.friends -le 2000) ){     # Follows between 501 and 2000 people
      switch($ratio){
        {$_ -le 1} {$index = 0}
        {($_ -gt 1) -and ($_ -le 1.5)}{$index = 4}
        {($_ -gt 1.5) -and ($_ -le 2)}{$index = 5}
        {($_ -gt 2) -and ($_ -le 2.5)}{$index = 7}
        {($_ -gt 2.5) -and ($_ -le 3)}{$index = 8}
        {$_ -gt 3}{$index = 10}
      }
    }elseif ($person.friends -gt 2000){ # Follows more than 2000 people
      switch($ratio){
        {$_ -le 1} {$index = 1}
        {($_ -gt 1) -and ($_ -le 1.5)}{$index = 5}
        {($_ -gt 1.5) -and ($_ -le 2)}{$index = 7}
        {($_ -gt 2) -and ($_ -le 2.5)}{$index = 9}
        {($_ -gt 2.5) -and ($_ -le 3)}{$index = 10}
        {$_ -gt 3}{$index = 10}
      }
    } # end evaluation of ratio when $person has followers
  } #end else ($person has followers)
  
  # Return index
  return $index 
} #END function get-RatioIndex

#-------------------------------------------
# eval-TwitterUser
# Description:  returns the spammer index for $person
# Parameters:   [twit]$person
# Output:       [int]$index
#
#-------------------------------------------
Function eval-TwitterUser([twit]$person){
  
  # Evaluate Ratio
  $ratioIndex = get-RatioIndex $person

  # Evaluate Friends
  $friendIndex = get-FriendIndex $person

  # Evaluate Bio
  $bioIndex = get-BioIndex $person

  # Evaluate Picture
  if (!($person.hasPic)){
    $picIndex = 2
  }else {
    $picIndex = 0
  }

  #Compute index
  $index = $ratioIndex + $friendIndex + $picIndex + $bioIndex
  
  return $index
} #END Function eval-TwitterUser

#-------------------------------------------
# Get-TwitterAge
# Description:  returns the age in days of a twitter date
# Parameters:   [string]$createdAt - in twitter date format (i.e. Tue Mar 06 16:56:23 +0000 2007)
# Output:       [int]$diff - difference between now and twitter creation day.
#
#-------------------------------------------
Function Get-TwitterAge([string] $createdAt){
  
  # Do some regex magic, split then merge back to a readable system.datetime string
  $date = $createdAt -replace " \+(\w*)", ""
  $date = $date.split(' ')
  $date = $date[0]+", "+$date[2]+" "+$date[1]+" "+$date[4]
  $date = [system.datetime]::parse($date)
  
  $now = get-date
  $diff = $now.Subtract($date).days
  
  return $diff
} #END Function Get-TwitterAge


#-------------------------------------------
# Get-TwitterFriendOrFollower
# Description:  Used to parse XML from twitter for either friend or follower
#               depending upon $command, returns array of Twits
# Parameters:   [string]$Username - Twitter username
#               [string]$Password - Twitter password
#               [string]$Command  - Either Friend or Follower
#               [string]$ID       - Optional 
# Output:       [Twit]$TwitList   - Array of Twits
#
#-------------------------------------------
Function Get-TwitterFriendOrFollower (  [string] $Username,
                                        [string] $Password,
                                        [string] $Command,
                                        [string] $ID )
{ 
  if ($WebClient -eq $null) {
    $Global:WebClient=new-object System.Net.WebClient
  }
  if ($Username) {
    $WebClient.Credentials =
      (New-Object System.Net.NetworkCredential -argumentList $Username, $Password)
  }
  if ($ID) {
    $URL="http://twitter.com/statuses/$Command/$ID.xml?page="
  }
  else {
    $URL="http://twitter.com/statuses/$Command.xml?page="
  }
  $page = 1
  $me = new-object Twit 
  $friends = @()
  
  [Twit[]]$TwitList = @()
  
  do {
    $rawResponse = $WebClient.DownloadString($url+$Page)
    $response = (([xml]($rawResponse)).users.user)
    if ($response -ne $null) {
      foreach ($u in $response) {
        $me.name = $u["screen_name"].psbase.InnerText
        $me.followers = $u["followers_count"].psbase.InnerText
        $me.friends = $u["friends_count"].psbase.InnerText
        $me.bio = $u["description"].psbase.InnerText
        $me.hasPic = (!($u["profile_image_url"].psbase.InnerText -eq $NULL))
        $me.age = get-TwitterAge $u["created_at"].psbase.InnerText
        $TwitList += $me
      }
    }
    $page ++
  } while ($response.count -gt 0)
  return $TwitList
} 

#-------------------------------------------
# Execute-HTTPPost
# Description:  Execute HTTP POST call on provided $url with $data
# Parameters:   [string]$url      - Url to request
#               [string]$data     - Data to include in post request
#-------------------------------------------
function Execute-HTTPPostCommand()
{
  param([string] $url = $null, [string] $data = $null);

  if ( $url -and $data )
  {
    [System.Net.WebRequest]$webRequest = [System.Net.WebRequest]::Create($url);
    $webRequest.ServicePoint.Expect100Continue = $false;
    if ( $url.ToLower().Contains("twitter.com") )
    {
      $webRequest.Credentials = Get-TwitterCredentials
      $webRequest.PreAuthenticate = $true;
    }
    $webRequest.ContentType = "application/x-www-form-urlencoded";
    $webRequest.Method = "POST";
    $webRequest.Headers.Add("X-Twitter-Client", "PoshTweet");
    $webRequest.Headers.Add("X-Twitter-Version", "1.0");
    $webRequest.Headers.Add("X-Twitter-URL", "http://devcentral.f5.com/poshtweet");
  
    [byte[]]$bytes = [System.Text.Encoding]::UTF8.GetBytes($data);
    $webRequest.ContentLength = $bytes.Length;
    [System.IO.Stream]$reqStream = $webRequest.GetRequestStream();
    $reqStream.Write($bytes, 0, $bytes.Length);
    $reqStream.Flush();
    [System.Net.WebResponse]$resp = $webRequest.GetResponse();
    $rs = $resp.GetResponseStream();
    [System.IO.StreamReader]$sr = New-Object System.IO.StreamReader -argumentList $rs;
    [string]$results = $sr.ReadToEnd();
    $results;
  }
}

#-------------------------------------------
# New-TwitterDirectMessage
# Description:  Sends a direct message to user $user with message $text
# Parameters:   [string]$user     - Target Twitter user
#               [string]$text     - Text to send
#-------------------------------------------
function New-TwitterDirectMessage()
{
  param([string]$user = $null, [string]$text = $null);
  if ( $user -and $text ){
    $enctext = [System.Web.HttpUtility]::UrlEncode("$text");
    $results = Execute-HTTPPostCommand "http://twitter.com/direct_messages/new.xml" "user=$user&text=$enctext"
    
  }
}

#-------------------------------------------
# block-TwitterUsers
# Description:  Blocks each twitter user in string $spammers
# Parameters:   [string]$spammers - String of Twitter spammers
#-------------------------------------------
function block-TwitterUsers([string]$spammers){
  
  $split = $spammers.split('@')
  foreach ($u in $split){
    if ($u -ne $null){
      $spam += $u
    }
  }
  $spam = $spam.split(' ')
  foreach ($id in $spam){
    $results = Execute-HTTPPostCommand "http://twitter.com/blocks/create/${id}.xml" "id=${id}";
  }
  
}

#-------------------------------------------
# Begin GUI
#-------------------------------------------

#-------------------------------------------
# PopUp
# Description:  Displays a popup with text $text
# Parameters:   [string]$text   - Text to display in popup
#-------------------------------------------
function PopUp ([string]$text){

#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$Reportingok = New-Object System.Windows.Forms.Button
$label1 = New-Object System.Windows.Forms.Label
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$Reportingok_OnClick= 
{
  $form1.close()

}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$form1.Text = 'Twisp'
$form1.Name = 'form1'
$form1.StartPosition = 4
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 161
$System_Drawing_Size.Height = 89
$form1.ClientSize = $System_Drawing_Size

$Reportingok.TabIndex = 1
$Reportingok.Name = 'Reportingok'
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 75
$System_Drawing_Size.Height = 23
$Reportingok.Size = $System_Drawing_Size
$Reportingok.UseVisualStyleBackColor = $True

$Reportingok.Text = 'OK'

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 45
$System_Drawing_Point.Y = 54
$Reportingok.Location = $System_Drawing_Point
$Reportingok.DataBindings.DefaultDataSourceUpdateMode = 0
$Reportingok.add_Click($Reportingok_OnClick)

$form1.Controls.Add($Reportingok)

$label1.TabIndex = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 108
$System_Drawing_Size.Height = 23
$label1.Size = $System_Drawing_Size
$label1.Text = $text

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 9
$label1.Location = $System_Drawing_Point
$label1.DataBindings.DefaultDataSourceUpdateMode = 0
$label1.Name = 'label1'

$form1.Controls.Add($label1)

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End PopUp

#-------------------------------------------
# GenerateForm
# Description:  Displays main form.
# Parameters:   [twit]$spammers - array of Twits
#-------------------------------------------
function GenerateForm ( $spammers )
{
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion

#region Generated Form Objects
$TwispMain = New-Object System.Windows.Forms.Form
$names = New-Object System.Windows.Forms.CheckedListBox
$textBox2 = New-Object System.Windows.Forms.TextBox
$exit = New-Object System.Windows.Forms.Button
$report = New-Object System.Windows.Forms.Button
$block = New-Object System.Windows.Forms.Button
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects


#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$block_OnClick= 
{
  $spammers = @()
  
  # Strip out the '@' before each name
  foreach ($u in $names.checkedItems){
    $temp = $u.split(' ')
    $block = $temp[0]
    $block = '@'+$block
    $spammers += $block
  }
  Block-TwitterUsers -spammers $spammers 
  popup "Blocking complete!" 
}

$exit_OnClick= 
{
  $TwispMain.close()
}

$report_OnClick= 
{
  $spammers = @()

  # Strip out the '@' before each name
  foreach ($u in $names.checkedItems){
    $temp = $u.split(' ')
    $block = $temp[0]
    $block = '@'+$block
    $spammers += $block
  }
  
  # Send DM to @spam reporting the users
  $user = "spam"
  New-TwitterDirectMessage $user $spammers
  popup "Reporting complete!"
  
  # Block the users
  Block-TwitterUsers -spammers $spammers
  popup "Blocking complete!"
}

$handler_checkedListBox1_SelectedIndexChanged= 
{

}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$TwispMain.WindowState = $InitialFormWindowState
}

#----------------------------------------------
# Generate Form stuff
$TwispMain.AutoSize = $True
$TwispMain.Text = 'Twisp'
$TwispMain.Name = 'TwispMain'
$TwispMain.StartPosition = 4
$TwispMain.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 582
$System_Drawing_Size.Height = 502
$TwispMain.ClientSize = $System_Drawing_Size

$names.FormattingEnabled = $True
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 546
$System_Drawing_Size.Height = 319
$names.Size = $System_Drawing_Size
$names.DataBindings.DefaultDataSourceUpdateMode = 0
$count = 0
foreach ($n in  $spammers){
  $text = $n.name+" "+$n.index
  $names.Items.Add($text)|Out-Null
  $count ++
}
$names.Name = 'names'
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 13
$System_Drawing_Point.Y = 117
$names.Location = $System_Drawing_Point
$names.TabIndex = 12
$names.add_SelectedIndexChanged($handler_checkedListBox1_SelectedIndexChanged)

$TwispMain.Controls.Add($names)

$textBox2.Multiline = $True
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 554
$System_Drawing_Size.Height = 94
$textBox2.Size = $System_Drawing_Size
$textBox2.DataBindings.DefaultDataSourceUpdateMode = 0
$textBox2.ReadOnly = $True
$textBox2.BorderStyle = 0
$textBox2.Text = 'The following users are canidates for being spam followers.

Their index of spamitude is indicated by the number following their name, the lower the number - the less likely they are spammers. 

I recommend you visit their twitter page prior to blocking or reporting the user unless you are sure they are spammers.

Any questions? Shoot me a reply @pezhore.'
$textBox2.Name = 'textBox2'
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 5
$System_Drawing_Point.Y = 5
$textBox2.Location = $System_Drawing_Point
$textBox2.TabIndex = 10

$TwispMain.Controls.Add($textBox2)

$exit.TabIndex = 5
$exit.Name = 'exit'
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 75
$System_Drawing_Size.Height = 23
$exit.Size = $System_Drawing_Size
$exit.UseVisualStyleBackColor = $True

$exit.Text = 'exit'

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 492
$System_Drawing_Point.Y = 467
$exit.Location = $System_Drawing_Point
$exit.DataBindings.DefaultDataSourceUpdateMode = 0
$exit.add_Click($exit_OnClick)

$TwispMain.Controls.Add($exit)

$report.TabIndex = 4
$report.Name = 'report'
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 75
$System_Drawing_Size.Height = 23
$report.Size = $System_Drawing_Size
$report.UseVisualStyleBackColor = $True

$report.Text = 'report'

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 104
$System_Drawing_Point.Y = 467
$report.Location = $System_Drawing_Point
$report.DataBindings.DefaultDataSourceUpdateMode = 0
$report.add_Click($report_OnClick)

$TwispMain.Controls.Add($report)

$block.TabIndex = 3
$block.Name = 'block'
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 75
$System_Drawing_Size.Height = 23
$block.Size = $System_Drawing_Size
$block.UseVisualStyleBackColor = $True

$block.Text = 'block'

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 13
$System_Drawing_Point.Y = 467
$block.Location = $System_Drawing_Point
$block.DataBindings.DefaultDataSourceUpdateMode = 0
$block.add_Click($block_OnClick)

$TwispMain.Controls.Add($block)

# End Generate Form stuff
#----------------------------------------------

#Save the initial state of the form
$InitialFormWindowState = $TwispMain.WindowState
#Init the OnLoad event to correct the initial state of the form
$TwispMain.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$TwispMain.ShowDialog()| Out-Null

} # END function GenerateForm ($spammers)

#-------------------------------------------
# End GUI
#-------------------------------------------

#-------------------------------------------
# Set-TwitterCredentials
# Description:  Sets the script's credentials to the specified 
#               username $user and password $pass. If no username
#               or password is provided, get the credentials
# Parameters:   [string]$user     - Credential username
#               [string]$pass     - Credential password
#-------------------------------------------
function Set-TwitterCredentials()
{
  param([string]$user = $null, [string]$pass = $null);

  if ( $user -and $pass ){
    $script:g_creds = New-Object System.Net.NetworkCredential -argumentList ($user, $pass);
  } else {
    $creds = Get-TwitterCredentials;
  }
}

#-------------------------------------------
# get-TwitterCredentials
# Description:  Sets the script's credentials to the specified 
#               username $user and password $pass. If no username
#               or password is provided, get the credentials
# Parameters:   [string]$user     - Credential username
#               [string]$pass     - Credential password
#-------------------------------------------
function Get-TwitterCredentials()
{
  # Check to see if global credentials have not been set
  if ( $null -eq $g_creds ){
    trap { Write-Error "ERROR: You must enter your Twitter credentials for Twisp to work!"; continue; }
    
    # Get the Credentials and set global g_creds
    $c = Get-Credential
    if ( $c ){
      $user = $c.GetNetworkCredential().Username;
      $pass = $c.GetNetworkCredential().Password;
      $script:g_creds = New-Object System.Net.NetworkCredential -argumentList ($user, $pass);
    }
  }
  $script:g_creds;
}

#######################################################################
#######################################################################
##                      END OF FUNCTIONS                             ##
#######################################################################
#######################################################################

# Set default null variables
[Twit[]]$dontFollow = @()     # Array of Twits the user doesn't follow
[Twit[]]$spammer = @()        # Array of Twits assessed to be spammers

# Get Credentials from user
Get-TwitterCredentials| Out-Null

# Populate array of friends
[Twit[]]$friends = Get-TwitterFriendOrFollower $g_creds.UserName $g_creds.Password "friends"

# Populate array of followers
[Twit[]]$followers = Get-TwitterFriendOrFollower $g_creds.Username $g_creds.Password "followers"  

# Iterate through followers
foreach ($u in $followers){
  $found = $FALSE
  
  # Iterate through friends
  foreach ($t in $friends){
    if ($u.name -eq $t.name){$found = $TRUE} # If the follower is also a friend, not a spammer
  }
  if (!($found)){
    $dontFollow += $u                        # Follower isn't a friend
  }
}

# Evaluate all twits not followed for Index of Spamitude
foreach ($u in $dontFollow){
  $index = eval-Twitteruser $u
  
  # If index is greater than min value add to spammer list
  if ($index -gt $minSpammer){
    $u.index = $index
    $spammer += $u 
  }
}

# Kick off GUI passing array of 
generateform $spammer